﻿//////////////////////////////////////////////////////////////////////////////////////////////////////
//Name: Bartosz
//FullName: Adamczewski
//Project: InternalClasses
//Component: InternalClasses
//StartDate: 2009-08-17 19:29:04
//EndDate: 2009-08-17 19:29:04
//Description: The implementation of InternalClasses component.
//Rights:  Copyright (c) Bartosz Adamczewski
////////////////////////////////////////////////////////////////////////////////////////////////////

#region imports.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Reflection.Emit;

#endregion

namespace InternalClasses.Dynamic
{
    /// <summary>
    /// The Dynamic Object class.
    /// </summary>
    public class DynamicObject : DynamicBase
    {
        private static readonly HybridDictionary dynamicObjectCache = new HybridDictionary();

        /// <summary>
        /// Clears the Dynamic Cache.
        /// </summary>
        public static void ClearDynamicCache()
        {
            dynamicObjectCache.Clear();
        }

        /// <summary>
        /// Creates an instance of the object dynamicly.
        /// </summary>
        /// <param name="target">the target type.</param>
        public static InstanceObjectInvoker CreateInstance(Type target)
        {
            if (dynamicObjectCache[target] == null)
            {
                System.Reflection.Emit.DynamicMethod dynamicMethod = new System.Reflection.Emit.DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object) }, target.Module);

                ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
                ilGenerator.DeclareLocal(target);
                ilGenerator.Emit(OpCodes.Newobj, target.GetConstructor(new Type[] { }));
                ilGenerator.Emit(OpCodes.Stloc_0);
                ilGenerator.Emit(OpCodes.Ldloc_0);
                ilGenerator.Emit(OpCodes.Ret);

                InstanceObjectInvoker invoker = (InstanceObjectInvoker)dynamicMethod.CreateDelegate(typeof(InstanceObjectInvoker));

                lock (dynamicObjectCache)
                {
                    dynamicObjectCache[target] = invoker;
                }

                return invoker;
            }
            else
            {
                return (InstanceObjectInvoker)dynamicObjectCache[target];
            }
        }
    }
}